package com.example.Windturbine.Service.Impl;

import com.example.Windturbine.Calculation.TreeDOMethod1.*;
import com.example.Windturbine.Controller.ViewObject.ResultVO.ListResultVO;
import com.example.Windturbine.Dao.*;
import com.example.Windturbine.DataObject.*;
import com.example.Windturbine.Error.BusinessException;
import com.example.Windturbine.Error.EmBusinessError;
import com.example.Windturbine.Service.*;
import com.example.Windturbine.Utils.MyThreadPool;
import lombok.SneakyThrows;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @Author 丁永新
 * @Date 2021/12/21
 */
@Service
public class ProductCalServiceImpl implements ProductCalService {

    @Resource
    ProductUseDOMapper productUseDOMapper;

    @Resource
    ProductDOMapper productDOMapper;

    @Resource
    LCAResultDOMapper lcaResultDOMapper;

    @Resource
    PartResultDOMapper partResultDOMapper;

    @Resource
    ProductResultDOMapper productResultDOMapper;

    @Resource
    ProductService productService;

    @Resource
    MaterialService materialService;

    @Resource
    TransportService transportService;

    @Resource
    ManufactureService manufactureService;

    @Resource
    ThreadPoolExecutor pool;

    @Resource
    RedisTemplate redisTemplate;

    @Autowired
    PartResultService partResultService;

    @Autowired
    ProductResultService productResultService;

    //提交计算方案
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
    public boolean submit(ProductUseDO productUseDO) throws BusinessException {
        int i = productUseDOMapper.insertSelective(productUseDO);
        if (i == 0) {
            throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, "插入失败");
        }
        TheMostImportCal(productUseDO);
        return true;
    }


    //查询用户所有计算方案
    @Override
    public List<ProductUseDO> getAll(Integer user_id) throws BusinessException {
        List<ProductUseDO> productUseDOS = productUseDOMapper.getAll(user_id);
        if (productUseDOS == null) {
            throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, "查询计算方案信息失败！");
        }
        return productUseDOS;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
    public void deleteById(Integer id) throws BusinessException {
        ProductUseDO productUseDO = productUseDOMapper.selectByPrimaryKey(id);
        if (productUseDO == null) {
            throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, "删除计算方案信息失败！");
        }
        //查询所有包含计算id的零件结果和产品结果
        List<PartResultDO> partResultDOS = partResultDOMapper.selectByCaliddAndProductid(id, productUseDO.getProductId());
        if (partResultDOS == null) {
            throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, "删除子零件计算信息失败！");
        }
        for (PartResultDO i : partResultDOS) {
            partResultService.deleteById(i.getId());
        }
        //删除产品
        ProductResultDO productResultDO = productResultDOMapper.selectByCaliddAndProductid(id, productUseDO.getProductId());
        if (productResultDO == null) {
            throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, "删除产品计算信息失败！");
        }
        productResultService.deleteById(productResultDO.getId());

        //删除计算结果
        int i = productUseDOMapper.deleteByPrimaryKey(id);
        if (i == 0) {
            throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, "删除失败！");
        }
    }

    private PartResultDO convertFrom(PartTree1 partTree1) {
        PartResultDO partResultDO = new PartResultDO();
        BeanUtils.copyProperties(partTree1, partResultDO);
        return partResultDO;
    }

    private ProductResultDO convertFrom(ProductRoot1 partTree1) {
        ProductResultDO partResultDO = new ProductResultDO();
        BeanUtils.copyProperties(partTree1, partResultDO);
        return partResultDO;
    }

    private LCAResultDO convertFromTree(LCAResult1 lcaResult1) {
        LCAResultDO lcaResultDO = new LCAResultDO();
        BeanUtils.copyProperties(lcaResult1, lcaResultDO);
        lcaResultDO.setPed(lcaResult1.getPED());
        lcaResultDO.setGwp(lcaResult1.getGWP());
        lcaResultDO.setAp(lcaResult1.getAP());
        lcaResultDO.setEp(lcaResult1.getEP());
        lcaResultDO.setOdp(lcaResult1.getODP());
        lcaResultDO.setPocp(lcaResult1.getPOCP());
        lcaResultDO.setGreenvalue(lcaResult1.getGreenvalue());
        return lcaResultDO;
    }


    //开始执行计算任务
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
    void TheMostImportCal(ProductUseDO productUseDO) throws BusinessException {
        //接下来进行零件的计算
        //判断用哪个方法
        if (productUseDO.getMethod() == 1) {
            LCA1 lca1 = new LCA1();
            try {
                lca1 = new LCA1(productDOMapper, productService, materialService, transportService, manufactureService, redisTemplate, productUseDO);
            } catch (Exception e) {
                throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, "初始化计算器失败！");
            }
            List<ProductInfoDO> productInfoDOList = new ArrayList<>();
            try {
                productInfoDOList = lca1.getSonPart();//排序过的列表
                //对子零件进行排序 子零件先计算 父零件再计算
            } catch (Exception e) {
                throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, "计算过程中获取子零件失败");
            }

            //遍历所有零部件转化为叶结点
            List<PartTree1> partTree1s = new ArrayList<>();

            for (ProductInfoDO p : productInfoDOList) {
                try {
                    PartTree1 temp = lca1.calLCA(p);
                    temp.setId(p.getId());
                    partTree1s.add(temp);
                } catch (Exception e) {
                    throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, "计算时信息转化失败！" + p.getNameInfo() + " " + p.getOrderInfo());
                }
            }

            //把产品结点转化为产品根结点
            ProductDO productDO = productDOMapper.selectByPrimaryKey(productUseDO.getProductId());
            if (productDO == null) {
                throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, "计算时 查询产品信息失败");
            }

            ProductRoot1 productRoot1 = new ProductRoot1();
            try {
                productRoot1 = lca1.calLCA(productDO, partTree1s);
                //把这些东西都存入数据库
            } catch (Exception e) {
                throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, "计算产品LCA数据发生错误！计算失败！");
            }

            try {

                //1 存入LCA零件的结果
                for (PartTree1 tree : partTree1s) {
                    //获取四个阶段的结果
                    LCAResult1 rawmaterialMiningStage = tree.getRawmaterialMiningStage();
                    LCAResult1 partTransportationStage = tree.getPartTransportationStage();
                    LCAResult1 manufacturingStage = tree.getManufacturingStage();
                    LCAResult1 recoveryStage = tree.getRecoveryStage();

                    //类转换
                    LCAResultDO raw = convertFromTree(rawmaterialMiningStage);
                    raw.setCalId(productUseDO.getId());
                    LCAResultDO part = convertFromTree(partTransportationStage);
                    part.setCalId(productUseDO.getId());
                    LCAResultDO man = convertFromTree(manufacturingStage);
                    man.setCalId(productUseDO.getId());
                    LCAResultDO recycle = convertFromTree(recoveryStage);
                    recycle.setCalId(productUseDO.getId());

                    raw = round(raw);
                    part = round(part);
                    man = round(man);
                    recycle = round(recycle);
                    //存零件阶段的结果
                    lcaResultDOMapper.insertSelective(raw);
                    lcaResultDOMapper.insertSelective(part);
                    lcaResultDOMapper.insertSelective(man);
                    lcaResultDOMapper.insertSelective(recycle);

                    //存零件的结果
                    PartResultDO partResultDO = new PartResultDO();
                    partResultDO.setCalId(productUseDO.getId());
                    partResultDO.setUserId(productUseDO.getUserId());
                    partResultDO.setProductId(productUseDO.getProductId());
                    partResultDO.setPartId(tree.getId());


                    partResultDO.setRawmaterialMiningStage(raw.getId());
                    partResultDO.setPartTransportationStage(part.getId());
                    partResultDO.setManufacturingStage(man.getId());
                    partResultDO.setRecoveryStage(recycle.getId());


                    partResultDOMapper.insertSelective(partResultDO);
                }
            } catch (Exception e) {
                throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, "存入零件计算信息时发生错误！");
            }


            try {
                //2 存入产品的计算结果
                LCAResult1 rawmaterialMiningStage = productRoot1.getRawmaterialMiningStage();
                LCAResult1 partTransportationStage = productRoot1.getPartTransportationStage();
                LCAResult1 manufacturingStage = productRoot1.getManufacturingStage();
                LCAResult1 productTransportationStage = productRoot1.getProductTransportationStage();
                LCAResult1 productUseStage = productRoot1.getProductUseStage();
                LCAResult1 recoveryStage = productRoot1.getRecoveryStage();

                LCAResultDO l1 = convertFromTree(rawmaterialMiningStage);
                LCAResultDO l2 = convertFromTree(partTransportationStage);
                LCAResultDO l3 = convertFromTree(manufacturingStage);
                LCAResultDO l4 = convertFromTree(productTransportationStage);
                LCAResultDO l5 = convertFromTree(productUseStage);
                LCAResultDO l6 = convertFromTree(recoveryStage);
                l1 = round(l1);
                l2 = round(l2);
                l3 = round(l3);
                l4 = round(l4);
                l5 = round(l5);
                l6 = round(l6);
                lcaResultDOMapper.insertSelective(l1);
                lcaResultDOMapper.insertSelective(l2);
                lcaResultDOMapper.insertSelective(l3);
                lcaResultDOMapper.insertSelective(l4);
                lcaResultDOMapper.insertSelective(l5);
                lcaResultDOMapper.insertSelective(l6);


                ProductResultDO productResultDO = new ProductResultDO();

                productResultDO.setRawmaterialMiningStage(l1.getId());
                productResultDO.setPartTransportationStage(l2.getId());
                productResultDO.setManufacturingStage(l3.getId());
                productResultDO.setProductTransportationStage(l4.getId());
                productResultDO.setProductUseStage(l5.getId());
                productResultDO.setRecoveryStage(l6.getId());

                productResultDO.setCalId(productUseDO.getId());
                productResultDO.setUserId(productUseDO.getUserId());
                productResultDO.setProductId(productUseDO.getProductId());

                productResultDOMapper.insertSelective(productResultDO);
            } catch (Exception e) {
                throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, "存入产品的计算结果时 出现错误！");
            }

        } else {

            throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, productUseDO.getMethod() + "方法暂时还未录入，敬请期待!");
        }
    }


    public LCAResultDO round(LCAResultDO lcaResult1) {
        lcaResult1.set煤(lcaResult1.get煤().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.set石油(lcaResult1.get石油().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.set天然气(lcaResult1.get天然气().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.setCo(lcaResult1.getCo().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.setCo2(lcaResult1.getCo2().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.setSo2(lcaResult1.getSo2().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.setNox(lcaResult1.getNox().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.setCh4(lcaResult1.getCh4().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.setH2s(lcaResult1.getH2s().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.setHcl(lcaResult1.getHcl().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.setCod(lcaResult1.getCod().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.setNh3(lcaResult1.getNh3().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.setCfc11(lcaResult1.getCfc11().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.setCfc12(lcaResult1.getCfc12().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.setCfc113(lcaResult1.getCfc113().setScale(20, BigDecimal.ROUND_HALF_DOWN));

        lcaResult1.setPed(lcaResult1.getPed().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.setGwp(lcaResult1.getGwp().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.setAp(lcaResult1.getAp().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.setEp(lcaResult1.getEp().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.setPocp(lcaResult1.getPocp().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.setOdp(lcaResult1.getOdp().setScale(20, BigDecimal.ROUND_HALF_DOWN));
        lcaResult1.setGreenvalue(lcaResult1.getGreenvalue().setScale(20, BigDecimal.ROUND_HALF_DOWN));

        return lcaResult1;
    }


}
